﻿#define USE_EMULATION

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.SharePoint;
using WindStyle.SPEntity;
using System.Collections;
using Microsoft.SharePoint.Emulators;
using Microsoft.QualityTools.Testing.Emulators;
using System.Linq;
using System.Collections.Generic;

namespace UnitTest
{
    [TestClass]
    public class EntityTest
    {

#if USE_EMULATION
        static readonly EmulationMode _emulationMode = EmulationMode.Enabled;
#else
        static readonly EmulationMode _emulationMode = EmulationMode.Passthrough;
#endif

        SharePointEmulationScope _emulationScope = new SharePointEmulationScope(_emulationMode);

        Context _context;

        [TestInitialize]
        public void Init()
        {
            this._context = new Context(_emulationMode);
        }

        [TestCleanup]
        public void Cleanup()
        {
            this._context.Dispose();
        }

        [TestMethod]
        public void NumberFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new NumberEntity();
            entity.Read(item);

            Assert.AreEqual(item.ID, entity.SPListItemId);
            Assert.AreEqual(Convert.ToInt32(item["Int"]), entity.Int);
            Assert.AreEqual(item["Double"], entity.Double);
            Assert.AreEqual(Convert.ToDecimal(item["Money"]), entity.Money);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.Int, Convert.ToInt32(newItem["Int"]));
            Assert.AreEqual(entity.Double, newItem["Double"]);
            Assert.AreEqual(entity.Money, Convert.ToDecimal(newItem["Money"]));
        }

        [TestMethod]
        public void DateTimeFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new DateTimeEntity();
            entity.Read(item);

            Assert.AreEqual(item["Date"], entity.Date);
            Assert.AreEqual(item["DateTime"], entity.DateTime);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.Date, newItem["Date"]);
            Assert.AreEqual(entity.DateTime, newItem["DateTime"]);
        }

        [TestMethod]
        public void StringFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new StringEntity();
            entity.Read(item);

            Assert.AreEqual(item["SingleLine"], entity.SingleLine);
            Assert.AreEqual(item["MultipleLine"], entity.MultipleLine);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.SingleLine, newItem["SingleLine"]);
            Assert.AreEqual(entity.MultipleLine, newItem["MultipleLine"]);
        }

        [TestMethod]
        public void BoolFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new BoolEntity();
            entity.Read(item);

            Assert.AreEqual(item["Bool"], entity.Bool);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.Bool, newItem["Bool"]);
        }

        [TestMethod]
        public void LinkFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new LinkEntity();

            var exceptionThrown = false;
            try
            {
                entity.Read(item);

                Assert.AreEqual(item["Link"].ToString(), entity.Link.Url + "," + entity.Link.Description);
                Assert.IsTrue(item["Image"].ToString().StartsWith(entity.ImageUrl.OriginalString));
                Assert.IsTrue(item["Image"].ToString().EndsWith(entity.ImageDescription));

            }
            catch (Exception e)
            {
                exceptionThrown = true;
            }
            Assert.IsTrue(exceptionThrown);

            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["Link"].ToString(), newItem["Link"].ToString());
        }

        [TestMethod]
        public void ChoiceFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new ChoiceEntity();
            entity.Read(item);

            Assert.AreEqual(Choice.Option2, entity.Choice);
            Assert.AreEqual(Choice.Option1 | Choice.Option2 | Choice.Option3, entity.Choices);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["Choice"], newItem["Choice"]);
            Assert.AreEqual(item["MultipleChoice"], newItem["MultipleChoice"]);
        }

        [TestMethod]
        public void LookupFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new LookupEntity();
            entity.Read(item);

            Assert.AreEqual(item["Lookup"].ToString(), entity.SubEntity.SPListItemId + ";#" + entity.SubEntity.Title);
            Assert.AreEqual(entity.SubEntity.SPListItemId, entity.SubEntityId);
            Assert.AreEqual(entity.SubEntity.Title, entity.SubEntityTitle);
            Assert.AreEqual(2, entity.SubEntities.Length);
            Assert.AreEqual(2, entity.SubEntityIds.Length);
            Assert.AreEqual(2, entity.SubEntityTitles.Length);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["Lookup"], newItem["Lookup"].ToString());
            Assert.AreEqual(item["MultipleLookup"].ToString(), newItem["MultipleLookup"].ToString());
        }

        [TestMethod]
        public void UserFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new UserEntity();
            entity.Read(item);

            Assert.AreEqual(item["User"].ToString(), entity.SPUser.ID + ";#" + entity.SPUser.Name);
            Assert.AreEqual(item["User"].ToString(), entity.User.Id + ";#" + entity.User.DisplayName);
            Assert.AreEqual(entity.User.Id, entity.UserId);
            Assert.AreEqual(entity.User.DisplayName, entity.UserName);
            Assert.AreEqual(2, entity.UserCollection.Count);
            Assert.AreEqual(2, entity.UserIds.Length);
            Assert.AreEqual(2, entity.UserNames.Length);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["User"].ToString(), newItem["User"].ToString());
            Assert.AreEqual("1;#Windie Chai;#2;#Kaneboy", newItem["Users"].ToString());

        }

        [TestMethod]
        public void ReadOnlyFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new ReadonlyFieldEntity();
            entity.Read(item);
            entity.SingleLine = Guid.NewGuid().ToString();

            var newItem = this._context.List.AddItem();
            var orignalValue = newItem["SingleLine"];
            entity.Write(newItem);

            Assert.AreEqual(orignalValue, newItem["SingleLine"]);
            Assert.AreNotEqual(entity.SingleLine, newItem["SingleLine"]);
        }

        [TestMethod]
        public void CustomConversionEntity()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new CustomConversionEntity();
            entity.Read(item);

            Assert.AreEqual("$" + item["Money"].ToString(), entity.Price);

            entity.Price = "$987.654";
            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.Price.Substring(1), newItem["Money"].ToString());
        }

        [TestMethod]
        public void ConverterCache()
        {
            var converter1 = ConverterProvider.GetConverterForField(typeof(double));
            var converter2 = ConverterProvider.GetConverterForField(typeof(double));
            Assert.AreEqual(converter1, converter2);
        }

        [TestMethod]
        public void Utilities()
        {
            List<SPListItem> items = new List<SPListItem>();
            items.Add(this._context.List.GetItemById(Context.ItemIds.Normal));
            items.Add(this._context.List.GetItemById(Context.ItemIds.Normal));
            items.Add(this._context.List.GetItemById(Context.ItemIds.Normal));
            items.Add(this._context.List.GetItemById(Context.ItemIds.Normal));
            items.Add(this._context.List.GetItemById(Context.ItemIds.Normal));

            var entities_5 = items.Convert<NumberEntity>();
            Assert.AreEqual(5, entities_5.Count());

            var entities_3 = items.Skip(2).Convert<NumberEntity>();
            Assert.AreEqual(3, entities_3.Count());

            var entities_2 = items.Take(2).Convert<NumberEntity>();
            Assert.AreEqual(2, entities_2.Count());

            var entities_1 = items.Skip(3).Take(1).Convert<NumberEntity>();
            Assert.AreEqual(1, entities_1.Count());
        }

        [TestMethod]
        public void NullValueOfFields()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Empty);

            new NumberEntity().Read(item);
            new DateTimeEntity().Read(item);
            new StringEntity().Read(item);
            new BoolEntity().Read(item);
            new LinkEntity().Read(item);
            new ChoiceEntity().Read(item);
            new LookupEntity().Read(item);
            new UserEntity().Read(item);
            new ReadonlyFieldEntity().Read(item);
        }

        [TestMethod]
        public void NotSupportFieldConverter()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new NotSupportFieldEntity();
            entity.Read(item);

            Assert.IsNull(entity.Value);
        }

        [TestMethod]
        public void CustomFieldConverter()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new CustomFieldEntity();
            entity.Read(item);

            Assert.AreEqual((item["CustomField"] as CustomFieldValue).Value, entity.Value);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["CustomField"].ToString(), newItem["CustomField"].ToString());
        }

        [TestMethod]
        public void CustomPropertyConverter()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            var entity = new CustomPropertyEntity();
            entity.Read(item);

            Assert.AreEqual(item["SingleLine"].ToString().ToCharArray()[4], entity.Property.Chars[4]);


            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(item["SingleLine"].ToString(), newItem["SingleLine"].ToString());
        }

        [TestMethod]
        public void String2GuidEntity()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Normal);
            item["SingleLine"] = Guid.NewGuid().ToString();
            var entity = new String2GuidEntity();
            entity.Read(item);

            Assert.AreEqual(item["SingleLine"], entity.Value.ToString());

            var newItem = this._context.List.AddItem();
            entity.Write(newItem);

            Assert.AreEqual(entity.Value.ToString(), newItem["SingleLine"]);
        }

        [TestMethod]
        public void NullableProperty()
        {
            var item = this._context.List.GetItemById(Context.ItemIds.Empty);
            var entity = new NullableEntity();
            entity.Read(item);

            Assert.IsFalse(entity.Bool.HasValue);
            Assert.IsFalse(entity.Choice.HasValue);
            Assert.IsFalse(entity.Choices.HasValue);
            Assert.IsFalse(entity.Date.HasValue);
            Assert.IsFalse(entity.Decimal.HasValue);
            Assert.IsFalse(entity.Double.HasValue);
            Assert.IsFalse(entity.Guid.HasValue);
            Assert.IsFalse(entity.Int.HasValue);



            var newItem = this._context.List.AddItem();
            entity.Write(newItem);
            Assert.IsNull(newItem["Bool"]);
            Assert.IsNull(newItem["Choice"]);
            Assert.IsNull(newItem["MultipleChoice"]);
            Assert.IsNull(newItem["Date"]);
            Assert.IsNull(newItem["Money"]);
            Assert.IsNull(newItem["Double"]);
            Assert.IsNull(newItem["Int"]);
            Assert.IsNull(newItem["SingleLine"]);



            item = this._context.List.GetItemById(Context.ItemIds.Normal);
            item["SingleLine"] = Guid.NewGuid().ToString();
            entity = new NullableEntity();
            entity.Read(item);

            Assert.IsTrue(entity.Bool.HasValue);
            Assert.IsTrue(entity.Choice.HasValue);
            Assert.IsTrue(entity.Choices.HasValue);
            Assert.IsTrue(entity.Date.HasValue);
            Assert.IsTrue(entity.Decimal.HasValue);
            Assert.IsTrue(entity.Double.HasValue);
            Assert.IsTrue(entity.Guid.HasValue);
            Assert.IsTrue(entity.Int.HasValue);

            Assert.AreEqual(item["Bool"].ToString(), entity.Bool.ToString());
            Assert.AreEqual(Choice.Option2, entity.Choice);
            Assert.AreEqual(Choice.Option1 | Choice.Option2 | Choice.Option3, entity.Choices);
            Assert.AreEqual(item["Date"], entity.Date);
            Assert.AreEqual(item["Money"].ToString(), entity.Decimal.ToString());
            Assert.AreEqual(item["Double"].ToString(), entity.Double.ToString());
            Assert.AreEqual(item["Int"].ToString(), entity.Int.ToString());
            Assert.AreEqual(item["SingleLine"].ToString(), entity.Guid.ToString());



            newItem = this._context.List.AddItem();
            entity.Write(newItem);
            Assert.IsNotNull(newItem["Bool"]);
            Assert.IsNotNull(newItem["Choice"]);
            Assert.IsNotNull(newItem["MultipleChoice"]);
            Assert.IsNotNull(newItem["Date"]);
            Assert.IsNotNull(newItem["Money"]);
            Assert.IsNotNull(newItem["Double"]);
            Assert.IsNotNull(newItem["SingleLine"]);
            Assert.IsNotNull(newItem["Int"]);

            Assert.AreEqual(entity.Bool.ToString(), item["Bool"].ToString());
            Assert.AreEqual(item["Choice"], newItem["Choice"]);
            Assert.AreEqual(item["MultipleChoice"], newItem["MultipleChoice"]);
            Assert.AreEqual(entity.Date, item["Date"]);
            Assert.AreEqual(entity.Decimal.ToString(), item["Money"].ToString());
            Assert.AreEqual(entity.Double.ToString(), item["Double"].ToString());
            Assert.AreEqual(entity.Guid.ToString(), item["SingleLine"].ToString());
            Assert.AreEqual(entity.Int.ToString(), item["Int"].ToString());
        }
    }
}
